package com.lry.pda;

import java.util.Stack;

/**
 * 带值栈的下推自动机
 *
 * stmt -> {0} expr {1} semi stmt | 空
 * expr -> term exprPrime
 * exprPrim -> plus {0} term {2} exprPrim | 空
 * term -> factor termPrime
 * termPrime -> time {0} factor {3} termPrime | 空
 * factor -> num {4} | ( expr )
 *
 */
public class AttrPdaParser {

    enum Grammar {
        STMT,
        EXPR,
        EXPR_PRIME,
        TERM,
        TERM_PRIME,
        FACTOR,
        NUM_OR_ID,
        PLUS,
        SEMI,
        MULTIPLE,
        LEFT_PARENT,
        RIGHT_PARENT,
        ACTION_0,   //{$1=$2=getname();} 申请内存
        ACTION_1,  //{freename($0);} 释放内存
        ACTION_2, //{System.out.println($$ + " += " + $0); freename($0);} +=
        ACTION_3, //{System.out.println($$ + " *= " + $0); freename($0);} *=
        ACTION_4  //{System.out.println($$ + " = " + lexer.yytext);} 赋值语句
    };


    //逆向将表达式压入栈中，遍历栈的时候发现栈顶是终结符，则终结符必须和lexer当前yytext匹配，若栈顶是非终结符，逆向将表达式压入栈中
    private Stack<Grammar> stack = new Stack<>();
    private Register register = new Register();
    private Stack<Attribute> valueStack = new Stack<>();
    private Lexer lexer;
    private Attribute parent = Attribute.getAttribute(new Attribute.KV());

    public static void main(String[] args) {
        AttrPdaParser pdaParser = new AttrPdaParser(new Lexer());
        pdaParser.parse();
    }


    public AttrPdaParser(Lexer lexer){
        this.lexer = lexer;
        this.lexer.input();
        this.lexer.advance();
        push(Grammar.STMT);
    }

    private void pop(){
        stack.pop();
        parent = valueStack.pop();

//        int size = stack.size();
//        for(int i=0;i<size;i++){
//            System.out.print(stack.get(i)+"("+valueStack.get(i)+")  ");
//        }
//        System.out.println();
    }

    private void push(Grammar grammar){
        stack.push(grammar);

        Attribute attribute = Attribute.getAttribute(parent.right);
        valueStack.push(attribute);

//        int size = stack.size();
//        for(int i=0;i<size;i++){
//            System.out.print(stack.get(i)+"("+valueStack.get(i)+")  ");
//        }
//        System.out.println();
    }

    public void parse(){
        while(!stack.isEmpty()){
            Grammar grammar = stack.peek();
            switch (grammar){

                //申请内存
                case ACTION_0:
                    stack.pop();
                    String name = register.getName();
                    int size = valueStack.size();
                    //将栈顶下面两个位置的right置为name

                    valueStack.get(size-2).right.key = name;
                    valueStack.get(size-3).right.key = name;

                    valueStack.pop();
                    break;

                    //释放内存
                case ACTION_1:
                    stack.pop();
                    Attribute attr = valueStack.pop();
                    name = attr.right.key;
                    register.free(name);
                    System.out.println("free "+name);
                    break;

                    //+=
                case ACTION_2:
                    stack.pop();
                    attr = valueStack.pop();
                    System.out.println(attr.left.key +" += " +attr.right.key);

                    attr.left.value += attr.right.value;
                    System.out.println(attr.left.key +" = " + attr.left.value);
                    //修改值栈
                    changeValue(attr.left.key,attr.left.value);

                    register.free(attr.right.key);
                    System.out.println("free "+attr.right.key);
                    break;

                    //*=
                case ACTION_3:
                    stack.pop();
                    attr = valueStack.pop();
                    System.out.println(attr.left.key +" *= " +attr.right.key);

                    attr.left.value *= attr.right.value;
                    System.out.println(attr.left.key +" = " + attr.left.value);

                    //修改值栈
                    changeValue(attr.left.key,attr.left.value);

                    register.free(attr.right.key);
                    System.out.println("free "+attr.right.key);
                    break;

                    //赋值
                case ACTION_4:
                    stack.pop();
                    attr = valueStack.pop();

                    changeValue(attr.right.key,Integer.valueOf(lexer.yytext));

                    System.out.println(attr.right.key +" = " +lexer.yytext);
                    lexer.advance();
                    break;

                //stmt -> {0} expr {1} semi stmt
                //        | 空
                case STMT:
                    //逆向压入表达式
                    pop();
                    if(lexer.match(Lexer.EOI)){
                        break;
                    }
                    push(Grammar.STMT);
                    push(Grammar.SEMI);
                    push(Grammar.ACTION_1);
                    push(Grammar.EXPR);
                    push(Grammar.ACTION_0);
                    break;

                //expr -> term exprPrime
                case EXPR:
                    pop();
                    push(Grammar.EXPR_PRIME);
                    push(Grammar.TERM);
                    break;

                //exprPrime -> plus {0} term {2} exprPrime
                // | 空
                case EXPR_PRIME:
                    pop();
                    if(!lexer.match(Lexer.PLUS)){
                        break;
                    }
                    push(Grammar.EXPR_PRIME);
                    push(Grammar.ACTION_2);
                    push(Grammar.TERM);
                    push(Grammar.ACTION_0);
                    push(Grammar.PLUS);
                    break;

                //term -> factor termPrime
                case TERM:
                    pop();
                    push(Grammar.TERM_PRIME);
                    push(Grammar.FACTOR);
                    break;

                //termPrime -> time {0} factor {3} termPrime
                //| 空
                case TERM_PRIME:
                    pop();
                    if(!lexer.match(Lexer.TIMES)){
                        break;
                    }
                    push(Grammar.TERM_PRIME);
                    push(Grammar.ACTION_3);
                    push(Grammar.FACTOR);
                    push(Grammar.ACTION_0);
                    push(Grammar.MULTIPLE);
                    break;

                //factor -> num {4}
                //| ( expr )
                case FACTOR:
                    pop();
                    if(lexer.match(Lexer.NUM_OR_ID)){
                        push(Grammar.ACTION_4);
                        push(Grammar.NUM_OR_ID);
                    }else if(lexer.match(Lexer.LP)){
                        push(Grammar.RIGHT_PARENT);
                        push(Grammar.EXPR);
                        push(Grammar.LEFT_PARENT);
                    }else {
                        parseError();
                    }
                    break;

                case NUM_OR_ID:
                    pop();
                    if(!lexer.match(Lexer.NUM_OR_ID)){
                        parseError();
                    }
                    //ACTION_4赋值语句需要yytext，所以此时不advance
//                    lexer.advance();
                    break;

                case PLUS:
                    pop();
                    if(!lexer.match(Lexer.PLUS)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case SEMI:
                    pop();
                    if(!lexer.match(Lexer.SEMI)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case MULTIPLE:
                    pop();
                    if(!lexer.match(Lexer.TIMES)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case LEFT_PARENT:
                    pop();
                    if(!lexer.match(Lexer.LP)){
                        parseError();
                    }
                    lexer.advance();
                    break;

                case RIGHT_PARENT:
                    pop();
                    if(!lexer.match(Lexer.RP)){
                        parseError();
                    }
                    lexer.advance();
                    break;
            }
        }
        System.out.println("PDA accept");
    }

    private void changeValue(String key,Integer value){
        //遍历值栈找到所有key是t0||t1...的，把value改成value
        for (Attribute attribute : valueStack) {
            if(key.equals(attribute.left.key)){
                attribute.left.value = value;
            }
            if(key.equals(attribute.right.key)){
                attribute.right.value = value;
            }
        }
    }

    private void parseError() {
        System.err.println("PDA parse error");
        System.exit(1);
    }

}
